<script lang="ts" setup>
import {
  defineComponent,
  onMounted,
  reactive,
  ref,
  watch,
  nextTick,
  computed,
  watchEffect
} from 'vue';
import { Message, Modal } from '@arco-design/web-vue';
import { onClickOutside } from '@vueuse/core';
import { useRoute } from 'vue-router';

const props = defineProps({
  /* 分类标题 */
  titles: {
    type: String,
    default: '分类名称'
  },
  /* 删除API函数 */
  delFn: {
    type: Function,
    default: () => {}
  },
  /* 获取tree API函数 */
  listFn: {
    type: Function,
    default: () => {}
  },
  /* 重命名API函数 */
  reNameFn: {
    type: Function,
    default: () => {}
  },
  /* 添加API函数 */
  addFn: {
    type: Function,
    default: () => {}
  },
  /* 搜索节点API函数 */
  searchFolderFn: {
    type: Function,
    default: () => {}
  },
  /* 是否有操作项 */
  isOperate: {
    type: Boolean,
    default: true
  },
  /* 根节点ID */
  rootId: {
    type: Number,
    default: -1
  },
  /* 是否可拖拽 */
  isDrop: {
    type: Boolean,
    default: false
  },
  /* 是否有模糊搜索 */
  isFuzzySearch: {
    type: Boolean,
    default: true
  },
  /* 是否有修改父级的操作 */
  isModifyParent: {
    type: Boolean,
    default: true
  },
  /* 重命名方法传参格式不同，一种传两个对象{id: ''}, {...params} 一种直接传一个对象,这里默认为第一种传参方式 */
  isReNameFnOne: {
    type: Boolean,
    default: true
  },
  /* 限制子集level不能超过3（看板那块有这个）, 其他不超过6 */
  isThreeChildren: {
    type: Boolean,
    default: false
  },
  /* 树是否展示数量 */
  isShowNum: {
    type: Boolean,
    default: false
  },
  /* 新建文件夹这些名称的后缀 */
  suffixName: {
    type: String,
    default: '文件夹'
  },
  /* 是否来源于场景管理(因为下面删除需要用到判断) */
  isFromScenes: {
    type: Boolean,
    default: false
  }
});
const emit = defineEmits(['fetchList']);
const treeList: any = ref([]);
const toggle = ref('-1'); // 当前hover到哪个节点上
const nodeName = ref('');
const inputRef = ref();
const modifyVisible = ref(false);
const modifyFormRef = ref();
const newNode: any = ref({});
const nodeEditName = ref(''); // 新增node的名称
const activeGroupId = ref(0);
const operateDropdown = ref(false);
const dropdownImg = ref();
const findChildArr = ref();
const findIndex = ref(-1);
const route = useRoute();

// 重命名，新建 名称暂存
const newOrEditName: any = ref('');
// 缓存id
const saveEditId: any = ref();
// tree  ref
const tree: any = ref();
const modifyForm = reactive({
  folderLevel: '',
  parentFolder: ''
});
const folderOption = ref([
  {
    label: '一级',
    value: 1
  },
  {
    label: '二级',
    value: 2
  },
  {
    label: '三级',
    value: 3
  }
]);
const previousFolderList = ref<any>([]); // 上级文件夹
const modifyOriginalId = ref(''); // 要去修改父级的目录原始id
const listLoading = ref(false);

// 点击显示操作项菜单
const showOperateDropdown = (id: number) => {
  activeGroupId.value = id;
  operateDropdown.value = !operateDropdown.value;
};

// 添加树层级
const listLevel = (arr: any, level: number) => {
  arr?.forEach((item: any) => {
    item.level = level;
    if (Array.isArray(item.children) && item.children.length > 0) {
      item.children = listLevel(item.children, level + 1);
    }
  });
  return arr;
};
// 获取树list
const getTreeNodeList = async (params?: any) => {
  // data: 0 场景管理树    data: 1 场景取数树
  let param: any = {
    ...params
  };
  if (route.name === 'IndexScenesManage') {
    param.data = 0;
  }
  if (route.name === 'applicationFetch') {
    param.data = 1;
  }
  listLoading.value = true;
  try {
    const { code, data }: any = await props?.listFn({ ...param });
    if (code === 200) {
      const arr = [];
      data?.children?.forEach((item: any) => {
        if (!item.parentId) {
          item.parentId = data.id;
        }
      });
      arr.push(data);
      treeList.value = arr;
      localStorage.setItem('treeListS', JSON.stringify(treeList.value));
      // 选中第一项
    }
  } catch (error) {
    console.log(error);
  } finally {
    listLoading.value = false;
  }
};

// 拖拽
const onDrop = ({ dragNode, dropNode }) => {
  if (dragNode.level === dropNode.level) {
    // 如果同级 就是上移下移的效果（上级id就是目标id的上一个，如果没有则直接给-1）
    let previousIdVal = getPreviousId(dropNode);
    let params = {
      id: dragNode.id,
      name: dragNode.name,
      parentId: dragNode.parentId,
      previousId: previousIdVal
    };
    reNameSubject(params);
  } else {
    Message.error('只支持同级拖动');
  }
};

// 点击获取节点的key
const selectNode = (id: number, level: number) => {
  console.log(id, '此时选中的id');
  activeGroupId.value = id;
  if (level === 0) {
    emit('fetchList', '');
  } else {
    emit('fetchList', id);
  }
};

// 搜索节点
const searchTreeNode = async (params?: any) => {
  activeGroupId.value = 0;
  getTreeNodeList({ name: nodeName.value });
};

// 点击重命名
const onReName = (data: any) => {
  operateDropdown.value = false;
  // 缓存名称和id
  newOrEditName.value = data.name;
  saveEditId.value = data.id;
  //启动编辑状态
  data.reName = true;
  setTimeout(() => {
    inputRef.value.focus();
  }, 500);
};
const reNameSubject = async (params: any) => {
  const param = { ...params };
  try {
    const { code, data } = await props?.reNameFn(
      { id: param.id },
      {
        name: param.name,
        parentId: param.parentId,
        previousId: param.previousId
      }
    );
    if (code === 200) {
      getTreeNodeList();
      nodeEditName.value = '';
      Message.success('更新成功');
    }
  } catch (error) {
    Message.error('更新失败');
  } finally {
    newOrEditName.value = '';
  }
};

// 定义一个轮询查找父级的children
const findChildren = (data: any, treeData: any, type: string) => {
  console.log(treeData, '此时树形结构', data, '传来的数据');
  treeData.forEach((item: any) => {
    if (item.id === data.parentId && item.level === data.level - 1) {
      console.log('进来了', item);
      // 如果匹配到就返回当前项的children及当前被点击节点的索引
      let nowIndex = item.children.findIndex(
        (subItem: any) => subItem.id === data.id
      );
      console.log(item.children, '****', nowIndex, '&&&');
      findChildArr.value = item.children;
      findIndex.value = nowIndex;
      console.log(
        findChildArr.value,
        '找到的数组',
        findIndex.value,
        '找到的索引'
      );
      switch (type) {
        // 点击向下添加（此时的previousId传当前被点击项的id）
        case 'next':
          newNode.value = {
            id: 'new',
            parentId: data.parentId,
            previousId: item.children[nowIndex].id,
            level: data.level
          };
          item.children.splice(nowIndex + 1, 0, newNode.value);
          break;
        // 点击向上添加（此时的previousId传当前被点击项的前一项 若当前为第一项 那直接传-1）
        case 'add':
          newNode.value = {
            id: 'new',
            parentId: data.parentId,
            previousId: nowIndex - 1 < 0 ? -1 : item.children[nowIndex - 1].id,
            level: data.level
          };
          item.children.splice(
            nowIndex - 1 < 0 ? 0 : nowIndex,
            0,
            newNode.value
          );
          break;
        case 'delete':
          if (nowIndex > -1) {
            item.children.splice(nowIndex, 1);
          }
          break;
        case 'rename':
          break;
      }
    } else {
      // 匹配不到就继续递归
      item.children && findChildren(data, item.children, type);
    }
  });
};

// 用来获取当前项的上一级的id
const getPreviousId = (data: any) => {
  findChildArr.value = [];
  findIndex.value = -1;
  findChildren(data, treeList.value, 'rename');
  if (findChildArr.value.length && findIndex.value > -1) {
    console.log(findChildArr.value);
    const previousId =
      findIndex.value - 1 < 0 ? -1 : findChildArr.value[findIndex.value - 1].id;
    return previousId;
  }
};

// 在上方添加文件夹
const addUp = (data: any) => {
  operateDropdown.value = false;
  findChildArr.value = [];
  findIndex.value = -1;
  findChildren(data, treeList.value, 'add');
  setTimeout(() => {
    inputRef.value.focus();
  }, 500);
};

// 在下方添加文件夹
const addNext = (data: any) => {
  operateDropdown.value = false;
  findChildArr.value = [];
  findIndex.value = -1;
  findChildren(data, treeList.value, 'next');
  setTimeout(() => {
    inputRef.value.focus();
  }, 500);
};

// 执行添加操作
const creatNewSubject = async (params?: any) => {
  try {
    const { code, data } = await props?.addFn({
      ...newNode.value
    });
    if (code === 200) {
      getTreeNodeList();
      Message.success('添加成功');
    }
  } catch (error) {
    Message.error('添加失败');
  } finally {
    newOrEditName.value = '';
  }
};

// 添加子文件夹
const addSon = (data: any) => {
  operateDropdown.value = false;
  let previousId = -1;
  if (data.children && data.children.length > 0) {
    previousId = data.children[data.children.length - 1].id;
  }
  newNode.value = {
    id: 'new',
    parentId: data.id,
    previousId,
    level: data.level + 1
  };
  data.children.push(newNode.value);
  nextTick(() => {
    tree.value.expandNode(data.id, true);
  });
  setTimeout(() => {
    inputRef.value.focus();
  }, 500);
};

// 删除
const fetchRemove = async (id: string) => {
  try {
    let res = await props?.delFn({ id });
    return res;
  } catch (error) {
    throw error;
  }
};
const remove = (id: string) => {
  saveEditId.value = id;
  Modal.confirm({
    modalClass: 'model-message-confirm',
    title: props.isFromScenes ? '是否确定删除该分类？' : '是否确定删除该目录？',
    content: '删除后不可恢复',
    simple: false,
    closable: true,
    okText: '确定删除',
    okButtonProps: {
      style: {
        backgroundColor: '#FF1A3B'
      }
    },
    onBeforeOk: (done) => {
      fetchRemove(id)
        .then((res: any) => {
          if (res.code === 200) {
            Message.success('删除成功');
            getTreeNodeList();
          } else {
            Message.error(res.msg);
          }
        })
        .finally(() => {
          done(true);
        });
    }
  });
};

// 根据层级查询文件夹
const getFolderFromLevel = async (params?: any) => {
  try {
    const { code, data } = await props?.searchFolderFn({
      ...params
    });
    if (code === 200) {
      console.log(data, '上级数据');
      previousFolderList.value = data;
    }
  } catch (error) {
    Message.error('修改失败');
  }
};

// 修改父级
const modifyParent = (data: any) => {
  operateDropdown.value = false;
  modifyVisible.value = true;
  modifyForm.folderLevel = data.level;
  modifyOriginalId.value = data.id;
  getFolderFromLevel({ level: data.level - 1, parentDirId: data.parentId });
};

// 关闭modal之前
const onBeforeOk = async (done: any) => {
  const err = await modifyFormRef.value.validate();
  if (!err) {
    done(true);
  } else {
    done(false);
  }
};

// 确定修改父级文件夹
const handleOk = async () => {
  try {
    const { code, data } = await props?.reNameFn(
      { id: modifyOriginalId.value },
      {
        parentId: modifyForm.parentFolder,
        previousId: -1 // 传-1放到最上面
      }
    );
    if (code === 200) {
      Message.success('修改成功');
      getTreeNodeList();
      modifyVisible.value = false;
      modifyFormRef.value.resetFields();
      modifyFormRef.value.clearValidate();
    }
  } catch (error) {
    Message.error('修改失败');
  }
};

// 取消修改
const handleCancel = () => {
  modifyVisible.value = false;
  modifyFormRef.value.resetFields();
  modifyFormRef.value.clearValidate();
};

// hover到节点上
const onMouseenter = (nodeId: string) => {
  toggle.value = nodeId;
};
// 鼠标离开节点
const onMouseleave = () => {
  toggle.value = '-1';
};

// 名称框失去焦点
const nameInputOnBlur = (data: any) => {
  if (data.id != 'new') {
    data.reName = false;
  } else {
    newOrEditName.value = '';
    findChildArr.value = [];
    findIndex.value = -1;
    // 移掉该节点
    findChildren(data, treeList.value, 'delete');
  }
};

// 新建分类（input框失焦 + 回车）
const creatSubject = (data: any) => {
  console.log('走到新建的位置了');
  newNode.value = {
    name: newOrEditName.value,
    parentId: data.parentId,
    previousId: data.previousId
  };
  if (newOrEditName.value === '') {
    Message.error('名称不能为空！');
  } else {
    // 在上，下，子添加分类
    if (data?.id === 'new' && data) {
      creatNewSubject();
    } else if (data?.id !== 'new' && data) {
      // 重命名
      reNameSubject({
        id: data?.id,
        name: newOrEditName.value,
        parentId: data.parentId,
        previousId: getPreviousId(data)
      });
    } else {
      console.log('新建一级主题');
      // 新建一级主题，非右侧菜单
      let previousId = -1;
      if (treeList.value.length > 0) {
        previousId = treeList.value[treeList.value.length - 1].id;
      }
      newNode.value = {
        parentId: -1,
        previousId,
        name: newOrEditName.value
      };
      creatNewSubject();
    }
  }
};

onClickOutside(dropdownImg, (event) => {
  operateDropdown.value = false;
});

// 页面加载后初始化
onMounted(() => {
  getTreeNodeList();
});

// 点击重置后选择全部
const handleAll = () => {
  nodeName.value = '';
  searchTreeNode();
  if (String(props.rootId).length) {
    selectNode(props.rootId, 0);
  } else {
    selectNode(-1, 0);
  }
};
defineExpose({ handleAll, getTreeNodeList });
</script>

<template>
  <div class="group-container">
    <div class="group-title">{{ props.titles }}</div>
    <div class="group-search">
      <a-input-search
        style="height: 30px"
        placeholder="请输入"
        @search="searchTreeNode"
        @clear="searchTreeNode"
        @pressEnter="searchTreeNode"
        v-model="nodeName"
        allow-clear
      />
    </div>
    <div class="tree-container">
      <a-tree
        class="groupTree"
        draggable
        blockNode
        :data="treeList"
        animation
        @drop="onDrop"
        v-if="treeList.length > 0"
        :default-selected-keys="[activeGroupId]"
        :selected-keys="[activeGroupId]"
        :fieldNames="{
          key: 'id',
          title: 'name',
          children: 'children'
        }"
        ref="tree"
        v-loading="listLoading"
      >
        <template #drag-icon></template>
        <template #title="nodeData">
          <a-input
            v-if="nodeData.reName || nodeData.id === 'new'"
            v-model="newOrEditName"
            style="width: 100%; height: 28px; margin-right: 15px"
            @keyup.enter.native="creatSubject(nodeData)"
            @blur="nameInputOnBlur(nodeData)"
            ref="inputRef"
            placeholder="请输入"
          >
            <template #suffix
              ><span style="color: #d4d7e1"> ↵ </span>
            </template>
          </a-input>

          <a-dropdown
            class="theme-dropdown tree-dropdown-operate"
            trigger="click"
            position="bl"
            :popup-visible="operateDropdown && activeGroupId === nodeData.id"
          >
            <div
              v-show="!nodeData.reName && nodeData.id !== 'new'"
              class="custom-tree-node"
              :class="
                nodeData.reName || nodeData.id === 'new'
                  ? 'custom-tree-node-input'
                  : activeGroupId === nodeData.id
                  ? 'custom-tree-node-name'
                  : ''
              "
              :style="activeGroupId === nodeData.id ? { color: '#316AFF' } : ''"
              @mouseleave="onMouseleave()"
              @mouseenter="onMouseenter(nodeData.id)"
              @click="selectNode(nodeData.id, nodeData.level)"
            >
              <div class="custom-tree-node-item">
                <el-tooltip
                  effect="dark"
                  :content="nodeData.name"
                  placement="top"
                >
                  <span class="node-name">
                    {{ nodeData.name }}
                  </span>
                </el-tooltip>
              </div>

              <span
                class="custom-tree-node-link"
                v-show="toggle === nodeData.id"
                ref="dropdownImg"
                @click.stop="showOperateDropdown(nodeData.id)"
                >· · ·</span
              >
            </div>
            <template
              #content
              v-if="nodeData.level === 0 || nodeData.id === -1"
            >
              <a-doption @click="addSon(nodeData)"
                >增加子{{ props.suffixName }}</a-doption
              >
            </template>
            <template #content v-else>
              <a-doption @click="onReName(nodeData)">重命名</a-doption>
              <a-doption
                @click="modifyParent(nodeData)"
                v-show="nodeData.level > 1"
                >修改父级</a-doption
              >
              <a-doption @click="addUp(nodeData)"
                >上方增加{{ props.suffixName }}</a-doption
              >
              <a-doption @click="addNext(nodeData)"
                >下方增加{{ props.suffixName }}</a-doption
              >
              <a-doption
                @click="addSon(nodeData)"
                v-show="
                  isThreeChildren ? nodeData.level < 3 : nodeData.level < 5
                "
                >增加子{{ props.suffixName }}</a-doption
              >
              <a-doption
                @click="remove(nodeData.id)"
                v-show="!nodeData.children || nodeData.children?.length === 0"
                >删除</a-doption
              >
            </template>
          </a-dropdown>
        </template>
      </a-tree>
    </div>
  </div>

  <!-- 修改父级出现的modal -->
  <a-modal
    v-model:visible="modifyVisible"
    :on-before-ok="onBeforeOk"
    @ok="handleOk"
    @cancel="handleCancel"
    unmountOnClose
    auto-label-width
    width="520px"
    modal-class="modify-modal"
  >
    <template #title>
      <span style="font-weight: bold"> 修改父级 </span>
    </template>
    <div>
      <a-form :model="modifyForm" class="modify-form" ref="modifyFormRef">
        <a-form-item
          field="folderLevel"
          label="文件夹层级"
          :rules="[{ required: true, message: '请选择文件夹层级' }]"
        >
          <a-select v-model="modifyForm.folderLevel" disabled>
            <a-option
              v-for="item of folderOption"
              :value="item.value"
              :label="item.label"
              :key="item.value"
            />
          </a-select>
        </a-form-item>
        <a-form-item
          field="parentFolder"
          label="上级文件夹"
          :rules="[{ required: true, message: '请选择上级文件夹' }]"
        >
          <a-select v-model="modifyForm.parentFolder">
            <a-option
              v-for="item of previousFolderList"
              :value="item.id"
              :label="item.name"
              :key="item.id"
            />
          </a-select>
        </a-form-item>
      </a-form>
    </div>
  </a-modal>
</template>

<style lang="scss" scoped>
@import './index.scss';
.tree-container {
  height: 100%;
  .tree-title {
    font-size: 16px;
    color: #33353b;
    font-weight: 600;
    height: 60px;
    line-height: 60px;
    border-bottom: 1px solid #e8ebf2;
    padding-left: 18px;
    margin-bottom: 12px;
  }
  .tree-search {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-bottom: 12px;
  }
  .tree-content {
    max-height: 500px;
    overflow-y: scroll;
    ::v-deep(.arco-tree) {
      .arco-tree-node {
        padding-left: 15px;
      }
    }
    ::v-deep(.arco-tree-node-title) {
      width: 100%;
      height: 100%;
      display: block;
      .tree-node-wrap {
        .tree-node-name {
          font-size: 14px;
          color: #33353b;
          letter-spacing: 0;
          line-height: 22px;
          font-weight: 400;
          padding: 4px auto;
        }
      }
    }
  }
}
</style>

<style lang="scss">
.tree-dropdown-operate {
  .arco-trigger-popup-wrapper {
    .arco-dropdown {
      padding: 0;
      .arco-dropdown-list-wrapper {
        max-height: none;
        width: 148px;
      }
    }
  }
}
.modify-modal {
  .arco-modal-body {
    padding: 18px 18px 0 16px;
  }
}
</style>
